/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.simple;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.ActionValueChangedRequestMessage;
import cn.easyplatform.messages.request.GetComboRequestMessage;
import cn.easyplatform.messages.vos.ActionValueChangedVo;
import cn.easyplatform.messages.vos.ComboVo;
import cn.easyplatform.messages.vos.datalist.ListActionValueChangedVo;
import cn.easyplatform.spi.service.ComponentService;
import cn.easyplatform.type.Constants;
import cn.easyplatform.type.DeviceType;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.ext.ComponentBuilder;
import cn.easyplatform.web.ext.zul.Actionbox;
import cn.easyplatform.web.ext.zul.Datalist;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.event.EventEntry;
import cn.easyplatform.web.task.event.FieldEntry;
import cn.easyplatform.web.task.zkex.ListSupport;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.BackendException;
import cn.easyplatform.web.task.support.scripting.ScriptUtils;
import cn.easyplatform.web.task.zkex.ComponentBuilderFactory;
import cn.easyplatform.web.task.zkex.list.PanelSupport;
import cn.easyplatform.web.utils.PageUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Window;

import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class ActionboxBuilder implements ComponentBuilder, EventListener<Event> {

    private OperableHandler main;

    private Actionbox ab;

    private ListSupport support;

    private Component anchor;

    public ActionboxBuilder(OperableHandler mainTaskHandler, Actionbox ab) {
        this.main = mainTaskHandler;
        this.ab = ab;
    }

    public ActionboxBuilder(ListSupport support, Actionbox ab, Component anchor) {
        this.support = support;
        this.main = support.getMainHandler();
        this.ab = ab;
        this.anchor = anchor;
    }

    @Override
    public Component build() {
        if (Strings.isBlank(ab.getMapping()))
            throw new EasyPlatformWithLabelKeyException(
                    "component.property.not.found", "<actionbox>", "mapping");
        if (Strings.isBlank(ab.getEntity()))
            throw new EasyPlatformWithLabelKeyException(
                    "component.property.not.found", "<actionbox>", "entity");
        if (ab.isCombo() && ab.isMultiple()) {
            if (ab.getMapping().split(",").length != 2)
                throw new EasyPlatformWithLabelKeyException(
                        "component.combo.match", "<actionbox>", "combo",
                        "mapping");
        }
        PageUtils.checkAccess(main.getAccess(), ab);
        ab.addEventListener(Events.ON_OPEN, this);
        if (ab.isAutocomplete() && !ab.isCombo() && !ab.isMultiple())
            ab.addEventListener(Events.ON_CHANGE, this);
        PageUtils.processEventHandler(main, ab, anchor);
        return ab;
    }

    @Override
    public void onEvent(Event event) throws Exception {
        if (event.getName().equals(Events.ON_OPEN))
            open(event.getPage());
        else
            select(event);
    }

    private void select(Event evt) {
        if (ab.hasAttribute("selectEvent"))
            return;
        Map<String, String> mapping = ScriptUtils.getMapping(ab.getMapping(),
                ab.getId());
        String src = mapping.get(ab.getId());
        ActionValueChangedVo avc = null;
        if (support == null) {//
            avc = new ActionValueChangedVo(ab.getEntity(), src, ab.getId(),
                    ab.getValue(), ab.getMapping());
        } else {
            if (main instanceof PanelSupport) {
                ListSupport ls = ((PanelSupport) main).getList();
                avc = new ListActionValueChangedVo(ab.getEntity(), src,
                        ab.getId(), ab.getValue(), ab.getMapping(), ls
                        .getComponent().getId(), null);
            } else {
                ListRowVo rv = support.getSelectedValue();
                avc = new ListActionValueChangedVo(ab.getEntity(), src,
                        ab.getId(), ab.getValue(), ab.getMapping(), support
                        .getComponent().getId(),
                        support.isCustom() ? rv.getData() : rv.getKeys());
            }
        }
        ComponentService cs = ServiceLocator
                .lookup(ComponentService.class);
        IResponseMessage<?> resp = cs
                .getActionValues(new ActionValueChangedRequestMessage(main
                        .getId(), avc));
        if (resp.isSuccess() && resp.getBody() != null) {
            ab.setAttribute("selectEvent", "on");
            try {
                String[] updateField = (String[]) resp.getBody();
                if (support == null)
                    main.refresh(new EventEntry<FieldEntry>(new FieldEntry(
                            updateField, true)));
                else {
                    OperableHandler list = (OperableHandler) support;
                    list.refresh(new EventEntry<FieldEntry>(new FieldEntry(
                            updateField, true)));
                }
            } finally {
                ab.removeAttribute("selectEvent");
            }
        }
    }

    @SuppressWarnings("unchecked")
    public void setLabel(Object value) {
        if (value == null || value.toString().trim().equals("")) {
            ab.setLabel("");
            return;
        }
        Object oldVal = value;
        if (ab.isMultiple() && "string".equals(ab.getValueType())) {
            value = value.toString().split("\\" + ab.getSeparator());
        }
        String sql = ab.getComboQuery();
        Object[] params = null;
        if (value instanceof Object[]) {
            params = (Object[]) value;
            if (params.length > 0) {
                int pos = sql.toUpperCase().indexOf(" WHERE ");
                String s = sql.substring(pos + 6).trim();
                StringBuilder sb = new StringBuilder(sql.substring(0, pos));
                sb.append(" WHERE (");
                for (int i = 0; i < params.length; i++) {
                    sb.append(s);
                    if (i < params.length - 1)
                        sb.append(" OR ");
                }
                sb.append(")");
                sql = sb.toString();
            }
        } else {
            params = new Object[1];
            params[0] = value;
        }

        if (params.length > 0) {
            ComponentService cs = ServiceLocator
                    .lookup(ComponentService.class);
            String name = null;
            if (ab.isMultiple())
                name = ab.getMapping().split("\\,")[0];
            else
                name = ab.getId().startsWith("#") ? ab.getId().substring(1)
                        : ab.getId();
            IResponseMessage<?> resp = cs.getCombo(new GetComboRequestMessage(
                    main.getId(),
                    new ComboVo(ab.getEntity(), name, sql, params)));
            if (!resp.isSuccess())
                throw new BackendException(resp);
            List<String> data = (List<String>) resp.getBody();
            if (!data.isEmpty()) {
                if (data.size() > 1) {
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < data.size(); i++) {
                        sb.append(data.get(i));
                        if (i < data.size() - 1)
                            sb.append(ab.getSeparator());
                    }
                    ab.setLabel(sb.toString());
                    sb = null;
                } else
                    ab.setLabel(data.get(0));
            } else
                ab.setLabel(oldVal.toString());
        }
    }

    private void open(Page page) {
        try {
            // if ("popup".equals(ab.getType())) {
            // if (ab.getFirstChild() == null) {
            // Window win = createContent();
            // Bandpopup popup = new Bandpopup();
            // if (!Strings.isBlank(ab.getPanelHeight())) {
            // int h = WebUtils.px0(ab.getPanelHeight());
            // if (h > 0)
            // popup.setHeight((h + 5) + "px");
            // else
            // popup.setHeight(ab.getPanelHeight());
            // } else
            // popup.setHeight("455px");
            // popup.appendChild(win);
            // ab.appendChild(popup);
            // ab.open();
            // }
            // } else {
            Window win = createContent();
            win.setPage(page);
            if (Contexts.getEnv().getDeviceType().equals(DeviceType.MOBILE.getName()))
                win.setMaximized(true);
            else
                win.setPosition(ab.getPosition());
            win.doModal();
            // }
        } catch (EasyPlatformWithLabelKeyException ex) {
            MessageBox.showMessage(
                    Labels.getLabel("message.dialog.title.error"),
                    Labels.getLabel(ex.getMessage(), ex.getArgs()));
        } catch (BackendException ex) {
            MessageBox.showMessage(ex.getMsg().getCode(), (String) ex.getMsg()
                    .getBody());
        }
    }

    private Window createContent() {
        if (Strings.isBlank(ab.getEntity())) {
            MessageBox.showMessage(Labels
                    .getLabel("message.dialog.title.error"), Labels.getLabel(
                    "component.property.not.found", new String[]{ab.getId(),
                            "entity"}));
            return null;
        }
        if (Strings.isBlank(ab.getMapping())) {
            MessageBox.showMessage(Labels
                    .getLabel("message.dialog.title.error"), Labels.getLabel(
                    "component.property.not.found", new String[]{ab.getId(),
                            "mapping"}));
            return null;
        }
        Datalist dl = new Datalist();
        dl.setEntity(ab.getEntity());
        dl.setId(ab.getId());
        dl.setType(Constants.ACTIONBOX);
        dl.setBefore(ab.getMapping());
        dl.setImmediate(true);
        dl.setPageSize(ab.getPageSize());
        dl.setInvisibleColumns(ab.getInvisibleColumns());
        dl.setSizedByContent(ab.isSizedByContent());
        if (dl.isSizedByContent())
            dl.setSpan(true);
        dl.setShowPanel(true);
        dl.setShowRowNumbers(ab.isShowRowNumbers());
        dl.setHeight(ab.getPanelHeight());
        dl.setWidth(ab.getPanelWidth());
        dl.setLevelBy(ab.getLevelBy());
        dl.setOrderBy(ab.getOrderBy());
        dl.setGroup(ab.getGroup());
        dl.setShowGroupCount(ab.isShowGroupCount());
        dl.setCondition(ab.getCondition());
        dl.setShowPanel(ab.isShowPanel());
        dl.setFrozenColumns(ab.getFrozenColumns());
        dl.setExport(ab.isExport());
        dl.setCheckall(ab.isCheckall());
        dl.setCheckmark(ab.isCheckmark());
        dl.setMultiple(ab.isMultiple());
        dl.setOddRowSclass(ab.getOddRowSclass());
        dl.setSpan(ab.isSpan());
        dl.setSizable(ab.isSizable());
        dl.setPagingDetailed(ab.isPagingDetailed());
        dl.setPagingAutohide(ab.isPagingAutohide());
        dl.setPagingMold(ab.getPagingMold());
        dl.setPagingStyle(ab.getPagingStyle());
        dl.setRowStyle(ab.getRowStyle());
        dl.setHeadStyle(ab.getHeadStyle());
        dl.setAuxHeadStyle(ab.getAuxHeadStyle());
        dl.setFootStyle(ab.getFootStyle());
        dl.setFrozenStyle(ab.getFrozenStyle());
        dl.setUseQueryResult(ab.isUseQueryResult());
        dl.setInit(ab.getInit());
        dl.setFilter(ab.getFilter());
        dl.setDepth(ab.getDepth());
        dl.setCache(ab.isCache());
        dl.setFetchAll(ab.isFetchAll());
        ComponentBuilder builder = ComponentBuilderFactory.getEntityBuilder(
                main, dl, ab, anchor);
        return (Window) builder.build();
    }
}
